# !/usr/bin/env python
# -*-coding:utf-8 -*-

"""
# File       : running_strategy.py
# Time       ：2023/8/1 10:26
# Author     ：YangYong
# version    ：python 3.10
# Description：
    任务运行策略
    task run strategy when task run error
"""
import json

from orderlines.execute.app_context import AppContext
from orderlines.execute.base_parse import BaseParse
from orderlines.execute.process_parse import TaskPatternContext
from orderlines.execute.states.process_finite_state_machines import ProcessInstanceState
from orderlines.execute.states.task_finite_state_machines import TaskInstanceState
from orderlines.execute.task_build import TaskBuild
from orderlines.utils.exceptions import OrderLineRunningException
from orderlines.utils.orderlines_enum import TaskStates
from orderlines.utils.utils import get_task_config_item
from public.logger import logger


class RunningStrategy(BaseParse):
    def __init__(
            self,
            process_instance_id: str,
            context: AppContext,
            current_task_id: str,
            task_instance_id: str,
            process_parse: TaskPatternContext,
            error_info: dict,
            task_build: TaskBuild,
            task_fsm: TaskInstanceState,
            process_fsm: ProcessInstanceState
    ):
        super(RunningStrategy, self).__init__(process_instance_id, context)
        self.current_task_id = current_task_id
        self.task_instance_id = task_instance_id
        self.process_parse = process_parse
        self.error_info = error_info
        self.task_build = task_build
        self.task_fsm = task_fsm
        self.process_fsm = process_fsm
        self._task_config = self.task_config(self.current_task_id)
        self.sleep_time = int(get_task_config_item(self._task_config, "sleep_time", 1))
        self.strategy_context = {
            'RAISE': self.raise_strategy,
            'SKIP': self.skip_strategy,
            'RETRY': self.retry_strategy
        }

    def skip_strategy(self):
        is_complete = self.process_parse.task_parse.is_complete()
        task_logs = logger.log_text(self.task_instance_id)
        self.task_fsm.trigger_chance('failure', self.error_info, task_logs)
        self.task_fsm.trigger_chance('skip', self.error_info, task_logs)
        return is_complete

    def raise_strategy(self):
        task_logs = logger.log_text(self.task_instance_id)
        self.task_fsm.trigger_chance('failure', self.error_info, task_logs)
        self.process_fsm.trigger_chance('failure', self.error_info)
        return False

    def retry_strategy(self):
        retry_time = int(self._task_config.get('retry_time'))
        time = 1
        while time < retry_time:
            try:
                run_log = f'Start retry {time} times, retry sleep time::{self.sleep_time}'
                logger.info(run_log, task_instance_id=self.task_instance_id)
                task_result = self.task_build.build(self.current_task_id, self.process_info, self.task_nodes)
                if isinstance(task_result, str):
                    task_result = json.loads(task_result)
                if task_result.get('status') == TaskStates.green.value:
                    is_complete = self.process_parse.task_parse.is_complete()
                    task_logs = logger.log_text(self.task_instance_id)
                    self.task_fsm.trigger_chance('success', task_result, task_logs)
                    return is_complete
                else:
                    raise OrderLineRunningException(f'task retry run error {task_result.get("error_info")}')
            except Exception as error:
                _error_info = f'The number of retries exceeded the maximum:{time}. Error message::{error}'
                self.error_info['error_info'] = _error_info
                logger.error(_error_info, task_instance_id=self.task_instance_id)
                time += 1

        self.error_info['status'] = TaskStates.red.value
        task_logs = logger.log_text(self.task_instance_id)
        self.task_fsm.trigger_chance('failure', self.error_info, task_logs)
        self.process_fsm.trigger_chance('failure', self.error_info)
        return False

    def handle_strategy(self) -> tuple:
        """
        处理异常的策略，Policy for handling exceptions
        @return:is_run:bool, error_info:dict, task_status:str
        """
        task_strategy = get_task_config_item(self._task_config, 'task_strategy', 'RAISE')
        if not isinstance(task_strategy, str):
            task_strategy = 'RAISE'
        run_log = f'任务ID:{self.current_task_id},task_strategy is {task_strategy}'
        logger.info(run_log, task_instance_id=self.task_instance_id)
        return self.strategy_context.get(task_strategy)()
